如何在 Docker 使用 GitLab CI
在 Docker 上安裝 GitLab
參考官方文件,撰寫Docker Compose。
version: '3.7'
services:
GitLab-Server:
image: 'gitlab/gitlab-ee:latest'
container_name: GitLab-Server
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'http://127.0.0.1:5080/'
nginx['listen_port'] = 80
gitlab_rails['gitlab_shell_ssh_port'] = 5022
ports:
- 5080:80
- 5443:443
- '5022:22'
privileged: true
volumes:
- .\Volumes\GitLab-Server\Config:/etc/gitlab
- data:/var/opt/gitlab
- .\Volumes\GitLab-Server\Logs:/var/log/gitlab
shm_size: '256m'
networks:
default:
ipv4_address: 172.20.0.2
restart: always
volumes:
data:
networks:
default:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.20.0.0/16
gateway: 172.20.0.1- 將指令游標切換至 docker-compose.yml 所在位置,並執行
docker-compose up -d運行 Container。 - 稍等幾分鐘後,在網頁輸入「http://127.0.0.1:5080」訪問GitLab Web,帳號預設為
root,密碼則存放至檔案(/srv/gitlab/config/initial_root_password)裡。 - 點選右上角頭像 > preferences > password,將密碼改成好記的密碼,並重新登入。
TIP
external_url不設定雖然可以連到網頁,但會有部分功能找不到網頁,且網域非所設定的 IP,而是一連串的英數字組合,或是在儲存庫上 SSH、http 裡記錄的複製儲存庫網址有這個問題。external_url最好設定成外部 IP 或是 Domain Name,這邊用127.0.0.1是因為雖然有指定 IP,但是無法使用主機使用設定 IP 連線(不過有時候設定又可能,暫時找不到原因)。- 當有設定
external_url時,使用非 80 port,則要設定nginx['listen_port'] = 80,如果是用 https ,則改為443,詳細原因請參照此篇文章。 - 50xx 的 Port 可以自行視需求變更如果出現「invalid port specification」的錯誤訊息,參考 Invalid port specification: 601342,將
5022:22用引號括起來。 external_url和gitlab_rails['gitlab_shell_ssh_port']的 port 設定與 ports 的對應關係要一致。- volumes 底下
/var/opt/gitlab的路徑綁定,官網範例雖然是用「Bind Mount」,但在「artifacts」功能會因權限功能無法正常,所以是用「Volume」連結。
GitLab 的設置
GitLab 目前有提供兩種設定方式:
- gitlab.rb:存放在「/srv/gitlab/config/」底下,更改設定後,執行指令更新 GitLab 設定
gitlab-ctl reconfigure來生效。 - Pre-configure:在 Docker 設定環境變數
GITLAB_OMNIBUS_CONFIG,此設定不會覆蓋 「gitlab.rb」,而是在每次執行docker run或是docker-compose up時,依所輸入的設定去更新 GitLab 設定,完整可支援的設定請參閱「gitlab.rb.template」。
在 Docker 上安裝 GitLab Runner
安裝方法可參考官方文件來設定 docker-compose,這邊將 GitLab Runner 的內容加至原先的 docker-compose.yml 裡面。
docker-compose.yml 裡 GitLab Runner的部分
services:
GitLab-Server:
#...GitLab-Server的內容,這裡先省略...
GitLab-Runner:
image: gitlab/gitlab-runner:latest
container_name: GitLab-Runner
privileged: true
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- .\Volumes\GitLab-Runner\Config:/etc/gitlab-runner
networks:
default:
ipv4_address: 172.20.0.3
restart: always
#...volumes和networks的內容,這裡先省略...TIP
如果有使用Docker Executor的話需要設定 /var/run/docker.sock:/var/run/docker.sock。
註冊 GitLab Runner
輸入指令 docker exec -it GitLab-Runner gitlab-runner register,其中字首大寫的「GitLab-Runner」為 在docker-compose 設定的 container_name,第二個全小寫的 gitlab-runner 為 gitlab-runner.exe。 當執行 Register 時,Command Line 會出現以下訊息,進行 Runner 的設定初始化。
Enter the GitLab instance URL => 可讓 Runner 連上 GitLab 的網址,如上面範例為
http://172.20.0.2。理論上複製 Token 頁面上會有網址可以複製,但是如果未設定external_url或是網址為127.0.0.1或localhost之類的網址的話,那邊的網址無法正常使用。Enter the registration token => GitLab 有三種 Scope 的 Runner 類型可以註冊,可參閱「The scope of runners」,取得 Token 的位置如下表:
Scope 描述 Token位置 Shared Runner 每個專案都可以使用。 GitLab Admin Area > Overview > Runners > 點擊按鈕「Register an instance runner」則會顯示 Token。 Group Runner 僅供特定專案群組可以使用。 CI/CD > Runners > 點擊按鈕「Register a group runner」則會顯示 Token。 Project-Specific Runner 只有指定專案可以使用。 Settings > CI/CD > 展開 Runners > Specific runners 區塊有顯示 Token。 Enter a description for the runner: 簡易輸入此 Runner 用途會做為此 Runner 的名稱,後面可在 GitLab 用戶界面中更改此值。
Enter tags for the runner (comma-separated): 可輸入 Runner 的環境、Executor等內容,供後續 GitLab CI 在執行時,可以搜尋到符合的 Runner,後面可在 GitLab 用戶界面中更改此值。
Enter optional maintenance note for the runner: 輸入一些給此 Runner 其他開發維護人員需了解的相關的資訊,可以輸入空白。
Enter an executor: ssh, docker+machine, docker-ssh+machine, kubernetes, virtualbox, custom, docker, docker-ssh, parallels, shell: 輸入建構環境的方法,例如使用 docker 建置測試環境則輸入 docker,完整訊息請參閱Executors,另外如果 Runner 是安裝在 Windows 環境底下,還有
docker-windows可以設定用來建置 Windows 平台的環境,不過目前支援環境不多。Enter the default Docker image: 如果輸入 docker 會顯示此訊息,輸入預設的 docker image,例如:
docker:stable。
設定完成後,會發現「\srv\gitlab-runner\config」產生一個檔案「config.toml」作為 Runner 的設定檔。如果更新設定檔後,正常是使用 gitlab-runner restart,但這邊 Runner 是建立在 Docker,官方是建議直接使用 docker restart GitLab-Runner 重啟 Container,GitLab-Runner 自行替換為自己設定的容器名稱。
各個平台註冊 Runner 的方法請參閱 Registering runners。 Runner 設定請參閱 Configuring GitLab Runner。
簡單的 GitLab CI 實例 (Linux)
前置作業
建立一個 Repository 為「TestCore」。
將「TestCore」 Clone到本機。
在「TestCore」建立一個 .NET 6 的專案,資料結構如下:
textTestCore │ .gitignore │ .gitlab-ci.yml │ README.md │ └───build │ │ Dockerfile │ └───src │ └───TestCore │ TestCore.sln │ TestCore │ ...幫「TestCore」註冊一個使用 Docker Executor 的 Runner,tags 為
docker和linux,並開啟「config.toml」進行以下調整:privileged改為true。volumes改為["/var/run/docker.sock:/var/run/docker.sock", "/cache"],讓 Runner Executor 使用主機外部的 Docker Engine。- 如果 GitLab 未設定
external_url或是設定為127.0.0.1、localhost之類的,則須加上clone_url。 network_mode設為gitlab_default,讓 Runner Executor 可以用連到 GitLab。
完整內容如下:
concurrent = 1
check_interval = 0
[session_server]
session_timeout = 1800
[[runners]]
name = "Run Linux Docker"
url = "http://172.20.0.2"
id = 1
token = "dayFwyc86q4TdQzYz_Ca"
token_obtained_at = 2022-10-19T07:09:03Z
token_expires_at = 0001-01-01T00:00:00Z
clone_url = "http://172.20.0.2"
executor = "docker"
[runners.custom_build_dir]
[runners.cache]
[runners.cache.s3]
[runners.cache.gcs]
[runners.cache.azure]
[runners.docker]
tls_verify = false
image = "docker:stable"
privileged = true
disable_entrypoint_overwrite = false
oom_kill_disable = false
disable_cache = false
volumes = ["/var/run/docker.sock:/var/run/docker.sock", "/cache"]
shm_size = 0
network_mode = "gitlab_default"WARNING
network_mode 不能設定成 host,否則 Runner 執行時,可能會造成 GitLab 忙碌無法回應。
Dockerfile內容
FROM mcr.microsoft.com/dotnet/sdk:6.0
WORKDIR /app
COPY ./publish ./
EXPOSE 80
ENV ASPNETCORE_URLS "http://+:80"
ENTRYPOINT ["dotnet", "TestCore.dll"].gitlab-ci.yml內容
stages:
- build
- list
- deploy
build-job:
stage: build
image: mcr.microsoft.com/dotnet/sdk:6.0
tags:
- 'docker'
- 'linux'
script:
- cd src/TestCore
- dotnet restore
- dotnet build --configuration Release
- dotnet publish --configuration Release --output ../../build/publish
artifacts:
paths:
- ./build/publish/*
expire_in: never
list-job:
stage: list
image: bitnami/git:latest
script:
- git config --global core.quotepath false
- git diff-tree -r --no-commit-id --name-status --diff-algorithm=minimal HEAD > changes.txt
artifacts:
paths:
- ./changes.txt
expire_in: never
tags:
- 'docker'
- 'linux'
deploy-job:
stage: deploy
tags:
- 'docker'
- 'linux'
variables:
CONTAINER_RELEASE_IMAGE: $CI_PROJECT_PATH_SLUG:latest
script:
- cd build
- docker build --tag $CONTAINER_RELEASE_IMAGE .
- docker stop $CI_PROJECT_NAME || true && docker rm $CI_PROJECT_NAME || true
- docker run -d -p 9080:80 --restart=always --name $CI_PROJECT_NAME $CONTAINER_RELEASE_IMAGE
environment:
name: production
url: http://127.0.0.1:9080.gitlab-ci.yml說明
這邊簡化分支部分,僅做一個簡化的流程範例
使用關鍵詞
- stages:定義有哪些要執行的 Stage 名稱和順序,名稱可自己設定。
- job:範例中的
build-job和deploy-job,名稱可自己設定。- stage:設定此 Job 屬於
stages裡的哪個 Stage。 - tags:設定執行的 Runner,例如我這邊設定
docker、linux,那就會只有設定docker、linux的 Runner 會執行,若找不到符合 Runner,則會停擺直到 timeout。 - image:因為是使用 Docker Executor,每個 Stage 都為一個 Docker Container,所以要設定此 Stage 所使用的 Image 環境,如果沒設定,就會使用 Runner 設定的 Default Image。
- variables:變數宣告。
- script:要在 Runner 裡執行的 Command Script。
- artifacts:設定成功後附加到作業的文件和目錄列表,由於每階段是獨立的 Container,所以執行後把像是編譯過後的程式進行上傳,在從下個 Stage 下載使用。
- paths:要上傳的檔案路徑。
- expire_in:保留時間。
- environment:要部署的環境設定
- name:環境名稱。
- 給外面連結 Url。
- stage:設定此 Job 屬於
流程說明
build-job
- 設定使用 Image 為
mcr.microsoft.com/dotnet/sdk:6.0,這邊最好和 Dockerfile 用的 Image 一致。 - State 開始時,會從 Repository 下載此次上傳版本的檔案、資料夾。
- 因為 Repository 的專案資料夾是放在
src/方案目錄/專案目錄,所以先用 cd 切換目錄到方案目錄底下,如果有多專案,則切換到要選擇的專案資料夾底下。 - 使用
dotnet restore做套件還原,不過官網說執行docker build會自動進行dotnet restore。 - 使用
- dotnet build --configuration Release,建置專案,因為這邊是範例,所以configuration 直接設定為Release,實務上應搭配分支決定 configuration。 - dotnet publish --configuration Release --output ../../build/publish發佈專案,並指定輸出資料夾。artifacts設定要保留的路徑檔案和時間。
list-job
使用
git config --global core.quotepath false來停止轉譯特殊字符,在輸出路徑時,中文會被當成特殊字符轉換掉,所以將core.quotepath設為false。產出異動清單,Command 說明如下:
- git diff-tree:透過比較兩個節點的樹對象,找到的差異的內容和模式,如果只輸入一個節點,則比較此節點與其父節點比較。
- -r:遞歸到子樹,若未設定只會比較一層。
- --no-commit-id:不顯示 Commit ID。
- --name-status:僅顯示更改文件的名稱和狀態。
- --diff-algorithm=minimal:選擇差異算法,使用最小差異。
- HEAD:當前分支的最後一次提交
如果需要針對匯出格式調整,請參考官方文章 diff-tree。
deploy-job
未設定 Image,所以會使用 Runner 定義的
docker:stable。State 開始時,除了下載 Repository 的檔案外,會額外將前面
artifacts設定的路徑檔案下載下來至「build/publish」底下,所以 build 結構如下。textbuild │ Dockerfile(來自Repository) │ └───publish/*(來自artifacts)切換目錄至「build」。
使用
docker build將 Dockerfile 和 「publish」底下檔案建置成 image可執行 Web 的image。嘗試移除同名的 Container。
使用
docker run將剛建置的 image 來啟動 Container。environment將 Container 裡的 Web Url 提供給部署裡的環境設定。
執行結果
CI/CD > Jobs
如果 State 有上傳檔案至 artifacts 裡,會出現可下載圖示,藍框可以下載異動清單,紅框可下載編譯後檔案。

Deployments > Environments
會顯示一個可用環境,點擊「開啟」後,會開啟網址為 http://127.0.0.1:9080 的網頁,不從這邊開啟,直接輸入網址也可以。

WARNING
- 網路有些做法是用
Docker in Docker(DIND),使用的Docker Image Tag會是 dind 結尾,不過此法建立的 Container 我不知要如何讓外部使用,所以選擇在 Runner 的「config.toml」裡,將 volumes 增加docker.sock的對應,此法會讓建立的 Image 和 Container 都掛載在外部的 Docker 底下。 - 「CI_」開頭的變數為系統內部變數,詳情參考 Predefined variables reference。
- 官網範例在建立 Image 是使用「CI_REGISTRY」開頭的變數,因為要啟用 Registry 相關功能要走 https,且要建立相應的
Access Token才可使用,這邊就不提了。 - Image 名稱只能為小寫,因為範例裡的 Repository 名稱有含大寫,所以使用
CI_PROJECT_PATH_SLUG。
參考資料來源
The .gitlab-ci.yml fileEnvironments and deploymentsgitlab-ci build asp.net core docker.Net & Docker(一)在Docker容器上運行.Net Core API
異動歷程
- 2022-10-24 初版文件建立。
